import os, subprocess, re
from BuildWizException import BuildWizException
from FileConfigurator import FileConfigurator
from Variable import Variable

class PlatformHelper:
    def __init__( self, filename):
        self.platFile = filename
        self.__loadedVars = []
        self.__sections2Delete = []
        self.__runMakeInstall = False
        self.__makeJobs = 0
        self.__enableBuild = False
        self.__nameID = ""
        self.__subvURL = ""
        self.__subvRevision = 0
        self.__deployInfo = {}
        self.__verifySubvUpdates = False
        self.possibleStatus = [ 'STATUS_NOT_BUILD'
                              , 'STATUS_READY_TO_BUILD'
                              , 'STATUS_BUILD_IN_PROGRESS'
                              , 'STATUS_BUILD_DONE'
                              , 'STATUS_BUILD_ERROR'
                              , 'STATUS_BUILD_FORCED_STOP' ]
        self.status = self.possibleStatus[ 0]
        self.__loadFile()
        self.__loadVarsFromFile()
        self.__buildFileName2Log = ""

    def getConfigFileName( self):
        return self.platFile

    def getPlatformName( self):
        return self.name

    def getID( self):
        return self.__nameID

    def getBuildDir( self):
        return self.buildDir

    def setBuildDir( self, builddir):
        self.buildDir = builddir

    def setStatus( self, value):
        if value in self.possibleStatus:
            self.status = value
        else:
            raise BuildWizException( "unknow status [%s]" % value)

    def setBuild( self, value):
        self.__enableBuild = value

    def isWaiting4Build( self):
        return self.__enableBuild

    def getStatus( self):
        return self.status

    def reloadFile( self):
        self.__loadFile()

    def __loadFile( self):
        if not os.path.isfile( self.platFile):
            return False
        try:
            self.__config = FileConfigurator( self.platFile)
            self.name = self.__config.getKeyValue( "platform", "name")

            self.buildDir = self.__config.getKeyValue( "platform", "builddir")
            if not os.path.isdir( self.buildDir):
                self.__try2CreateBuildDir()

            # If path is, ie. './dir/subdir/subsubdir', the result of the
            # following statement will be 'subsubdir'
            #self.__nameID = os.path.split( self.buildDir)[ 1]
            self.__nameID = self.name
            self.__cmakelistsDir = self.__config.getKeyValue( "platform", "cmakelistsDir")
            self.__projectDir = self.__config.getKeyValue( "platform", "projectdir")
            self.__description = str( self.__config.getKeyValue( "platform", "description"))

            if self.__config.getKeyValue( "make", "run_install") == 'True':
                self.__runMakeInstall = True
            else:
                self.__runMakeInstall = False

            self.__makeJobs = int( self.__config.getKeyValue( "make", "jobs"))

            self.__scriptBefore = self.__config.getKeyValue( "scripts", "before")
            if self.__config.getKeyValue( "scripts", "run_before") == 'True':
                self.__runScriptBefore = True
            else:
                self.__runScriptBefore = False

            self.__scriptAfter = self.__config.getKeyValue( "scripts", "after")
            if self.__config.getKeyValue( "scripts", "run_after") == 'True':
                self.__runScriptAfter = True
            else:
                self.__runScriptAfter = False

            if self.__config.getKeyValue( "subversion", "verify_updates") == "True":
                self.__verifySubvUpdates = True
            else:
                self.__verifySubvUpdates = False

            self.__subvURL = self.__config.getKeyValue( "subversion", "url")

            revision = self.__config.getKeyValue( "subversion", "current_revision")
            if revision == "":
                self.__subvRevision = -1
            else:
                self.__subvRevision = int( self.__config.getKeyValue( "subversion", "current_revision"))

            if self.__subvURL == "" and self.__subvRevision == -1:
                result = self.__getSubversionInfo4BuildDir()
                if len( result):
                    self.__subvURL = result[ "url"]
                    self.__subvRevision = result[ "revision"]

            # PENDRIVE DEPLOYMENT
            self.__deployPenSourceDir = self.__config.getKeyValue( "deploy_pen", "source_dir")
            self.__deployPenDestDir = self.__config.getKeyValue( "deploy_pen", "destiny_dir")
            self.__deployPenDirName = self.__config.getKeyValue( "deploy_pen", "dir_name")
            self.__deployPenDirNameDateTime = self.__config.getKeyValue( "deploy_pen", "dir_name_datetime")
            self.__deployPenLinkName = self.__config.getKeyValue( "deploy_pen", "link_2_dest_dir")
            if self.__config.getKeyValue( "deploy_pen", "umount_after_deploy") == "True":
                self.__deployPenUmount = True
            else:
                self.__deployPenUmount = False

            if self.__config.getKeyValue( "deploy_pen", "deploy_after_build_process") == "True":
                self.__deployPenAfterBuild = True
            else:
                self.__deployPenAfterBuild = False
            self.__fontOutput = self.__config.getKeyValue( "preferences", "font_output_window")

        except BuildWizException, e:
            print "Ooops in PlatformHelper.__loadFile(), ", e

    def __loadVarsFromFile( self):
        if self.__config:
            try:
                self.__loadedVars = []
                cmkVars = self.__config.getKeyValue( "CMAKE_VARIABLES_NAMES", "names")
                self.__cmkVars = self.__getVariables( cmkVars, True)

                cmkDefVars = self.__config.getKeyValue( "CMAKE_DEFINITIONS_NAMES", "names")
                self.__cmkDefVars = self.__getVariables( cmkDefVars)

                self.__loadedVars = self.__cmkVars + self.__cmkDefVars

            except BuildWizException, e:
                print "Ooops in PlatformHelper.__loadVarsFromFile(), ", e

    # TODO: criar essa funcao
    def __try2CreateBuildDir( self):
        return

    def __getVariables( self, variablesNames, isCMakeVar = False):
        try:
            variables = []
            value = ''
            varnames = variablesNames.split()
            for varEntry in varnames:
                # 'value' is always a string value
                vartype = self.__config.getKeyValue( varEntry, "type")
                value = self.__config.getKeyValue( varEntry, "value")
                var = Variable( varEntry, vartype, value, isCMakeVar)    
                variables.append( var)
        except BuildWizException, e:
            print "Ooops in PlatformHelper.__getVariables(), ", e
        return variables

    def __reloadVariables( self):
        self.__loadVarsFromFile()
        
    def getCMakeListsDir( self):
        return self.__cmakelistsDir

    def setCMakeListsDir( self, newdir):
        self.__cmakelistsDir = newdir

    def getProjectDir( self):
        return self.__projectDir

    def setProjectDir( self, newdir):
        self.__projectDir = newdir

    def getDescription( self):
        return self.__description

    def setDescription( self, descr):
        self.__description = descr

    def getAllVariables( self):
        self.__reloadVariables()
        return self.__loadedVars

    def getCMakeCommand( self):
        command = "cmake " + self.__cmakelistsDir + " "
        if len( self.__loadedVars) > 0:
            for var in self.__loadedVars:
                if len( var.getValue()) > 0:
                    command = command + " " + var.getFormattedStr()
        return command

    def addVariable( self, newVar):
        #print ">> addVariable(): name=%s type=%s value=%s" % (newVar.getName(), newVar.getType(), newVar.getValue())
        for varitem in self.__loadedVars:
            if newVar.getName() == varitem.getName():
                raise BuildWizException( "there is a variable [" 
                                    + newVar.getName() 
                                    + "] already under control for this platform")
        self.__loadedVars.append( newVar)
        return True

    def __getCmkAndDefVarsNames( self):
        cmk = []
        defs = []
        for var in self.__loadedVars:
            if var.isCMakeVar():
                #print "vai retornar uma var CMake: [%s]" % var.getName()
                cmk.append( var.getName())
            else:
                #print "vai retornar uma Define: [%s]" % var.getName()
                defs.append( var.getName())

        return cmk, defs

    def __persistVariable( self, var):
        """Creates and saves a new variable"""
        sectionName = var.getName()
        if self.__config.addSection( sectionName):
            #print "persisting %s:%s=%s" % (sectionName, var.getType(), var.getValue())
            self.__config.set( sectionName, "type", var.getType())
            self.__config.set( sectionName, "value", var.getValue())

    def __getVar( self, name, container):
        for v in container:
            if v.getName() == name:
                return v
        return None

    def __saveVariables( self, varnames, container, isCMakeSet = False):
        for section in varnames:
            var2BeSaved = self.__getVar( section, self.__loadedVars)
            if self.__getVar( section, container) != None:
                # It means this variable was one of those loaded from the original file,
                # so let's just set its value even if it has not changed by the user.
                #print 'to be saved: %s=%s' % (section, var2BeSaved.getValue())
                self.__config.set( section, "value", var2BeSaved.getValue())
            else:
                self.__persistVariable( var2BeSaved) # This is a new variable

        if isCMakeSet:
            self.__config.set( "CMAKE_VARIABLES_NAMES", "names", " ".join( varnames))
        else:
            self.__config.set( "CMAKE_DEFINITIONS_NAMES", "names", " ".join( varnames))

    def setDeployPenValues( self, penSettings):
        for key in penSettings.keys():
            self.__config.set( "deploy_pen", key, penSettings[ key])

    def getDeployPenValues( self):
        penSettings = {}
        penSettings[ "source_dir"] = self.__deployPenSourceDir
        penSettings[ "destiny_dir"] = self.__deployPenDestDir
        penSettings[ "dir_name"] = self.__deployPenDirName
        penSettings[ "dir_name_datetime"] = self.__deployPenDirNameDateTime
        penSettings[ "link_2_dest_dir"] = self.__deployPenLinkName
        penSettings[ "umount_after_deploy"] = self.__deployPenUmount
        penSettings[ "deploy_after_build_process"] = self.__deployPenAfterBuild
        return penSettings

    def setDeployPenSourceDir( self, dir):
        self.__deployPenSourceDir = dir
    def getDeployPenSourceDir( self):
        return self.__deployPenSourceDir
    def setDeployPenDestDir( self, dir):
        self.__deployPenDestDir = dir
    def getDeployPenDestDir( self):
        return self.__deployPenDestDir
    def setDeployPenDirName( self, dirname):
        self.__deployPenDirName = dirname
    def getDeployPenDirName( self):
        return self.__deployPenDirName
    def setDeployPenDirNameDateTime( self, datetime):
        self.__deployPenDirNameDateTime = datetime
    def getDeployPenDirNameDateTime( self):
        return self.__deployPenDirNameDateTime
    def setDeployPenLinkName( self, linkname):
        self.__deployPenLinkName = linkname
    def getDeployPenLinkName( self):
        return self.__deployPenLinkName
    def setDeployPenUmount( self, shouldUmount):
        self.__deployPenUmount = shouldUmount
    def getDeployPenUmount( self):
        return self.__deployPenUmount

    def saveConfigs( self):
        cmkVarNames, defVarNames = self.__getCmkAndDefVarsNames() 
        self.__saveVariables( cmkVarNames, self.__cmkVars, True)
        self.__saveVariables( defVarNames, self.__cmkDefVars)
        self.__config.deleteSections( self.__sections2Delete)
        self.__config.set( "make", "run_install", self.__runMakeInstall)
        self.__config.set( "make", "jobs", self.__makeJobs)
        self.__config.set( "scripts", "before", self.__scriptBefore)
        self.__config.set( "scripts", "after", self.__scriptAfter)
        self.__config.set( "scripts", "run_before", self.__runScriptBefore)
        self.__config.set( "scripts", "run_after", self.__runScriptAfter)
        self.__config.set( "platform", "builddir", self.buildDir)
        self.__config.set( "platform", "projectdir", self.__projectDir)
        self.__config.set( "platform", "cmakelistsdir", self.__cmakelistsDir)
        self.__config.set( "platform", "description", self.__description)
        self.__config.set( "subversion", "verify_updates", self.__verifySubvUpdates)
        self.__config.set( "preferences", "font_output_window", self.__fontOutput)

        # PenDeploy were set before - see: self.setDeployPenValues()

        self.__config.write()
        self.reloadFile()

    def setVariable( self, name, type, value):
        v = self.__getVar( name, self.__loadedVars)
        if v:
            v.setType( type)
            v.setValue( value)

    def delVariable( self, varname):
        v = self.__getVar( varname, self.__loadedVars)
        if v:
            del self.__loadedVars[ self.__loadedVars.index( v)]
            self.__sections2Delete.append( varname)

        # Just to keep consistency among containers...
        v = self.__getVar( varname, self.__cmkVars)
        if v:
            del self.__cmkVars[ self.__cmkVars.index( v)]
        else:
            v = self.__getVar( varname, self.__cmkDefVars)
            if v:
                del self.__cmkDefVars[ self.__cmkDefVars.index( v)]

    def setRunMakeInstall( self, runMakeInstall):
        self.__runMakeInstall = runMakeInstall 

    def setNumMakeJobs( self, numJobs):
        self.__makeJobs = numJobs

    def isRunMakeInstall( self):
        return self.__runMakeInstall

    def getNumMakeJobs( self):
        return self.__makeJobs

    def getScriptBefore( self):
        return self.__scriptBefore

    def setScriptBefore( self, file):
        self.__scriptBefore = file

    def getScriptAfter( self):
        return self.__scriptAfter

    def setScriptAfter( self, file):
        self.__scriptAfter = file

    def getRunScriptBefore( self):
        return self.__runScriptBefore

    def setRunScriptBefore( self, runIt):
        self.__runScriptBefore = runIt

    def getRunScriptAfter( self):
        return self.__runScriptAfter

    def setRunScriptAfter( self, runIt):
        self.__runScriptAfter = runIt

    def getBuildFileName2Log( self, logdir):
        if len( self.__buildFileName2Log) == 0:
            path = os.path.join( os.getcwd() + logdir) # ***ATTENTION*** to 'os.getcwd()'
            name = self.name + ".build"
            self.__buildFileName2Log = os.path.join( path, name)
        
        return self.__buildFileName2Log

    def setVerifySubversionUpdates( self, verifyOrNot):
        self.__verifySubvUpdates = verifyOrNot

    def isVerifySubversionUpdates( self):
        return self.__verifySubvUpdates

    def getSubversionURL( self):
        return self.__subvURL

    def setSubversionURL( self, url):
        self.__subvURL = url

    def getSubversionRevision( self):
        return self.__subvRevision

    def setSubversionRevision( self, revision):
        self.__subvRevision = revision 

    def isWorkingCopyUpdated( self):
        infoFromHead = self.__getSubversionInfo4BuildDir( True)
        infoFromWorkingCopy = self.__getSubversionInfo4BuildDir()
        if infoFromHead[ "revision"] > infoFromWorkingCopy[ "revision"]:
            return False
        else:
            return True

    def getWorkingCopyStatus( self):
        cmdList = []
        cmdList.append( "cd " + self.__projectDir)
        cmdList.append( "svn status")
        cmd = " && ".join( cmdList)
        proc = subprocess.Popen( cmd, shell=True
                               , stdin=subprocess.PIPE
                               , stdout=subprocess.PIPE
                               , stderr=subprocess.STDOUT) # send errors to stdout
        stdoutValue = str( proc.communicate()[ 0])
        return stdoutValue 

    def isWorkingCopy( self):
        return os.path.isdir( os.path.join( self.__projectDir, ".svn"))

    def __getSubversionInfo4BuildDir( self, infoFromHead = False):
        result = {}
        subvdir = os.path.join( self.__projectDir, ".svn")
        if os.path.isdir( subvdir):
            cmdList = []
            cmdList.append( "cd " + self.__projectDir)
            if infoFromHead:
                cmdList.append( "svn info --revision=HEAD")
            else:
                cmdList.append( "svn info")
            cmd = " && ".join( cmdList)
            proc = subprocess.Popen( cmd, shell=True
                                   , stdin=subprocess.PIPE
                                   , stdout=subprocess.PIPE
                                   , stderr=subprocess.STDOUT) # send errors to stdout
            stdoutValue = str( proc.communicate()[ 0])
            m = re.search( "URL: (.*)", stdoutValue)
            if m:
                result[ "url"] = m.group( 1)
                m = re.search( "Revision: (.*)", stdoutValue)
                if m:
                    result[ "revision"] = int( m.group( 1))

        return result


    def getDeployInfo( self):
        values = self.getDeployPenValues()
        if len( values) > 0:
            self.__deployInfo[ "pen"] = values

        return self.__deployInfo
        
    def setFontOutput( self, fontname):
        self.__fontOutput = fontname
        
    def getFontOutput( self):
        return self.__fontOutput

